#pragma once
#include <queue>
#include <mutex>
#include <thread>
#include <memory>
#include <condition_variable>
namespace ms{
    namespace work{

        template<class task>
        class work_max
        {
        public:
            work_max() : _stop(true) { ; }
            ~work_max()
            {
                WorkStop();
            }

            virtual void WorkStart()
            {
                if (_stop)
                {
                    _stop = false;
                    _threadptr = std::make_shared<std::thread>(std::bind(&work_max::WorkRun, this));
                }
            }
            virtual void WorkStop()
            {
				if (!_stop)
				{
					_stop = true;
					_cond.notify_all();
					_threadptr->join();
					std::lock_guard<std::mutex> guard(_mutex);
					while (!_taskqueue.empty())
					{
// 						delete _taskqueue.front();
						_taskqueue.pop();
					}
				}  
            }
            void PushTask(std::shared_ptr<task> task)
            {
                std::lock_guard<std::mutex> guard(_mutex);
                _taskqueue.push(task);
                _cond.notify_one();
            }
            bool QueueIsEmpty()
            {
                std::lock_guard<std::mutex> guard(_mutex);
                return _taskqueue.empty();
            }
            void SetQueueMax(size_t max)
            {
                task_max_ = max;
            }
            bool IsStart()
            {
                return !_stop;
            }
        protected:
            std::queue<std::shared_ptr<task>> _taskqueue;
            size_t task_max_{ 1000 };
            bool _stop;
            std::mutex _mutex;
            std::mutex _threadwait;
            std::condition_variable _cond;
            std::shared_ptr<std::thread> _threadptr;

        protected:
            virtual void RunTask()
            {
                if (QueueIsEmpty())
                {
                    std::unique_lock <std::mutex> lck(_threadwait);
                    _cond.wait(lck);
                    return;
                }
                std::shared_ptr<task> ptask;
                {
                    std::lock_guard<std::mutex> guard(_mutex);
                    ptask = _taskqueue.front();
                }
                if ((*ptask)())
                {
                    std::lock_guard<std::mutex> guard(_mutex);
                    _taskqueue.pop();
                }
                else
                {
                    std::lock_guard<std::mutex> guard(_mutex);
                    while (_taskqueue.size() > task_max_)
                    {
                        _taskqueue.pop();
                    }
                }
            }
            virtual void WorkRun()
            {
                while (!_stop)
                {
                    RunTask();
                }
            }
        };

    }
}